package org.unidata.mdm.data.service.segments;

import java.util.Objects;

import org.unidata.mdm.core.context.DataRecordContext;
import org.unidata.mdm.core.type.model.EntityElement;
import org.unidata.mdm.data.context.BatchAwareContext;
import org.unidata.mdm.data.context.ExternalIdResettingContext;
import org.unidata.mdm.data.exception.DataExceptionIds;
import org.unidata.mdm.data.exception.DataProcessingException;
import org.unidata.mdm.data.type.keys.RecordKeys;
import org.unidata.mdm.data.type.keys.RecordOriginKey;

/**
 * Supports external id autogeneration.
 * @author Mikhail Mikhailov on May 18, 2020
 */
public interface ExternalIdAutogenerationSupport {
    /**
     * Applies autogeneration rules for external ids.
     *
     * @param wrapper the wrapper
     * @param ctx the context
     * @return true, if applied, false otherwise
     */
    default void setupExternalIdAutogeneration(EntityElement wrapper, ExternalIdResettingContext ctx) {

        // 1. Not a RDC or this entity does not define generation strategy
        if (!(ctx instanceof DataRecordContext)
         || Objects.isNull(wrapper)
         || !wrapper.isGenerating()) {
            return;
        }

        // 2. Check this context is missing ext. id only, but is otherwise valid
        if (!ctx.isEtalonRecordKey()
         && !ctx.isOriginRecordKey()
         && !ctx.isEnrichmentKey()
         && !ctx.isLsnKey()
         && (Objects.isNull(ctx.getExternalId()) && Objects.nonNull(ctx.getEntityName()) && Objects.nonNull(ctx.getSourceSystem()))) {

            Object externalId = wrapper.getGenerating().generate((DataRecordContext) ctx);
            if (externalId == null) {
                return;
            }

            // 2.1 Check key length
            if (externalId.toString().length() > 512) {
                final String message = "Unable to generate externalId, using autogeneration strategy for entity {}. "
                        + "Generated key length exceeds the limit of 512 characters.";
                throw new DataProcessingException(message,
                        DataExceptionIds.EX_DATA_UPSERT_ID_GENERATION_STRATEGY_KEY_LENGTH,
                        ctx.getEntityName());
            }

            ctx.setExternalId(externalId.toString());

            // 2.2 Batch insert with keys
            if ((ctx instanceof BatchAwareContext) && ((BatchAwareContext) ctx).isBatchOperation() && Objects.nonNull(ctx.keys())) {

                RecordKeys suppliedKeys = ctx.keys();
                RecordKeys keys = RecordKeys.builder(suppliedKeys)
                        .originKey(RecordOriginKey.builder(suppliedKeys.getOriginKey())
                                .externalId(externalId.toString())
                                .build())
                        .build();

                ctx.keys(keys);
            }
        }
    }
}
